package com.awesome.img.util

import android.content.Context
import android.graphics.*
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.media.ExifInterface
import android.text.TextUtils
import androidx.annotation.DrawableRes
import com.awesome.img.bean.CompressParam
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.lang.reflect.Field

/**
 * Author: JFangZ
 * Email:janezhang1901@163.com
 * Date:2021/4/23 15:32
 * Description:The util for bitmap.
 */
object BitmapUtil {

    private fun blur(`in`: IntArray, out: IntArray, width: Int, height: Int, radius: Float) {
        val widthMinus1 = width - 1
        val r = radius.toInt()
        val tableSize = 2 * r + 1
        val divide = IntArray(256 * tableSize)
        for (i in 0 until 256 * tableSize) {
            divide[i] = i / tableSize
        }
        var inIndex = 0
        for (y in 0 until height) {
            var outIndex = y
            var ta = 0
            var tr = 0
            var tg = 0
            var tb = 0
            for (i in -r..r) {
                val rgb = `in`[inIndex + clamp(i, 0, width - 1)]
                ta += rgb shr 24 and 0xff
                tr += rgb shr 16 and 0xff
                tg += rgb shr 8 and 0xff
                tb += rgb and 0xff
            }
            for (x in 0 until width) {
                out[outIndex] =
                    divide[ta] shl 24 or (divide[tr] shl 16) or (divide[tg] shl 8) or divide[tb]
                var i1 = x + r + 1
                if (i1 > widthMinus1) {
                    i1 = widthMinus1
                }
                var i2 = x - r
                if (i2 < 0) {
                    i2 = 0
                }
                val rgb1 = `in`[inIndex + i1]
                val rgb2 = `in`[inIndex + i2]
                ta += (rgb1 shr 24 and 0xff) - (rgb2 shr 24 and 0xff)
                tr += (rgb1 and 0xff0000) - (rgb2 and 0xff0000) shr 16
                tg += (rgb1 and 0xff00) - (rgb2 and 0xff00) shr 8
                tb += (rgb1 and 0xff) - (rgb2 and 0xff)
                outIndex += height
            }
            inIndex += width
        }
    }

    private fun clamp(x: Int, a: Int, b: Int): Int {
        return if (x < a) a else if (x > b) b else x
    }

    private fun blurFractional(
        `in`: IntArray, out: IntArray, width: Int, height: Int, radius: Float
    ) {
        var localRadius = radius
        localRadius -= localRadius
        val f = 1.0f / (1 + 2 * localRadius)
        var inIndex = 0
        for (y in 0 until height) {
            var outIndex = y
            out[outIndex] = `in`[0]
            outIndex += height
            for (x in 1 until width - 1) {
                val i = inIndex + x
                val rgb1 = `in`[i - 1]
                val rgb2 = `in`[i]
                val rgb3 = `in`[i + 1]
                var a1 = rgb1 shr 24 and 0xff
                var r1 = rgb1 shr 16 and 0xff
                var g1 = rgb1 shr 8 and 0xff
                var b1 = rgb1 and 0xff
                val a2 = rgb2 shr 24 and 0xff
                val r2 = rgb2 shr 16 and 0xff
                val g2 = rgb2 shr 8 and 0xff
                val b2 = rgb2 and 0xff
                val a3 = rgb3 shr 24 and 0xff
                val r3 = rgb3 shr 16 and 0xff
                val g3 = rgb3 shr 8 and 0xff
                val b3 = rgb3 and 0xff
                a1 = a2 + ((a1 + a3) * localRadius).toInt()
                r1 = r2 + ((r1 + r3) * localRadius).toInt()
                g1 = g2 + ((g1 + g3) * localRadius).toInt()
                b1 = b2 + ((b1 + b3) * localRadius).toInt()
                a1 *= f.toInt()
                r1 *= f.toInt()
                g1 *= f.toInt()
                b1 *= f.toInt()
                out[outIndex] = a1 shl 24 or (r1 shl 16) or (g1 shl 8) or b1
                outIndex += height
            }
            out[outIndex] = `in`[width - 1]
            inIndex += width
        }
    }

    /**
     * Author: JFangZ
     * Email:janezhang1901@163.com
     * Date:2021/4/26 9:42
     * Description:Get mime type of bitmap.
     */
    fun getType(bytes: ByteArray): String? {
        val options = BitmapFactory.Options()
        options.inJustDecodeBounds = true
        BitmapFactory.decodeByteArray(bytes, 0, bytes.size, options)
        val mimeType = options.outMimeType ?: return null
        val split = mimeType.split("/").toTypedArray()
        return if (split.size < 2) {
            null
        } else split[1]
    }

    /**
     * Author: JFangZ
     * Email:janezhang1901@163.com
     * Date:2021/4/26 9:42
     * Description:Get mime type of bitmap.
     */
    fun getType(context: Context, @DrawableRes resId: Int): String? {
        val options = BitmapFactory.Options()
        options.inJustDecodeBounds = true
        BitmapFactory.decodeResource(context.resources, resId, options)
        val mimeType = options.outMimeType ?: return null
        val split = mimeType.split("/").toTypedArray()
        return if (split.size < 2) {
            null
        } else split[1]
    }

    /**
     * Author: JFangZ
     * Email:janezhang1901@163.com
     * Date:2021/4/26 9:42
     * Description:Get mime type of bitmap.
     */
    fun getType(path: String?): String? {
        val options = BitmapFactory.Options()
        options.inJustDecodeBounds = true
        BitmapFactory.decodeFile(path)
        val mimeType = options.outMimeType ?: return null
        val split = mimeType.split("/").toTypedArray()
        return if (split.size < 2) {
            null
        } else split[1]
    }

    /**
     * Author: JFangZ
     * Email:janezhang1901@163.com
     * Date:2021/4/23 15:33
     * Description:Drawable convert to bitmap.
     *
     */
    fun drawable2Bitmap(drawable: Drawable): Bitmap {
        val width = drawable.intrinsicWidth
        val height = drawable.intrinsicHeight
        val config =
            if (drawable.opacity != PixelFormat.OPAQUE) Bitmap.Config.ARGB_8888 else Bitmap.Config.RGB_565
        val result = Bitmap.createBitmap(width, height, config)
        val canvas = Canvas(result)
        drawable.setBounds(0, 0, width, height)
        drawable.draw(canvas)
        return result
    }

    /**
     * Author: JFangZ
     * Email:janezhang1901@163.com
     * Date:2021/4/23 15:33
     * Description:Bitmap convert to drawable.
     *
     */
    fun bitmap2Drawable(context: Context, bitmap: Bitmap?): Drawable {
        return BitmapDrawable(context.resources, bitmap)
    }


    /**
     * Author: JFangZ
     * Email:janezhang1901@163.com
     * Date:2021/4/23 15:33
     * Description:Bitmap convert to byte array.
     */
    fun bitmap2ByteArray(bitmap: Bitmap): ByteArray {
        val byteArrayOutputStream = ByteArrayOutputStream()
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream)
        return byteArrayOutputStream.toByteArray()
    }

    /**
     * Author: JFangZ
     * Email:janezhang1901@163.com
     * Date:2021/4/23 15:33
     * Description:Bitmap save to file.
     */
    fun bitmap2File(bitmap: Bitmap, file: File) {
        val fileOutputStream = FileOutputStream(file)
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream)
        fileOutputStream.flush()
        fileOutputStream.close()
    }


    /**
     * Author: JFangZ
     * Email:janezhang1901@163.com
     * Date:2021/4/23 15:39
     * Description:Compress bitmap,both size and quality size.
     */
    fun compress(src: File, dst: File, compressParam: CompressParam) {
        val options = BitmapFactory.Options()
        // Just load bitmap bounds for get width and height.
        options.inJustDecodeBounds = true
        BitmapFactory.decodeFile(src.absolutePath, options)

        // Calculate sample size.
        var sampleSize = 1
        val dstWidth: Int = compressParam.width
        val dstHeight: Int = compressParam.height
        while (options.outWidth / sampleSize > dstWidth || options.outHeight / sampleSize > dstHeight) {
            sampleSize *= 2
        }
        // Size compress.
        // Load bitmap content according to sample size.
        options.inJustDecodeBounds = false
        options.inSampleSize = sampleSize
        options.inPreferredConfig = Bitmap.Config.ARGB_8888
        val bitmap = BitmapFactory.decodeFile(src.absolutePath, options)
        val byteArrayOutputStream = ByteArrayOutputStream()
        var quality = 100
        // Quality compress.
        // Compress bitmap until size is less than target size.
        val targetSize: Int = compressParam.size
        while (byteArrayOutputStream.size() == 0 || byteArrayOutputStream.size() > targetSize) {
            byteArrayOutputStream.reset()
            quality = (quality * 0.8).toInt()
            bitmap.compress(Bitmap.CompressFormat.JPEG, quality, byteArrayOutputStream)
        }
        bitmap.recycle()
        // Output file.
        var fileOutputStream: FileOutputStream? = null
        try {
            fileOutputStream = FileOutputStream(dst)
            fileOutputStream.write(byteArrayOutputStream.toByteArray())
            fileOutputStream.flush()
            fileOutputStream.close()
        } catch (e: Exception) {
            e.printStackTrace()
        } finally {
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close()
                } catch (e: IOException) {
                    e.printStackTrace()
                }
            }
        }
        // Save meta-data.
        val srcExifInterface = ExifInterface(src.absolutePath)
        val dstExifInterface = ExifInterface(dst.absolutePath)
        val cls = ExifInterface::class.java
        val fields: Array<Field> = cls.fields
        for (i in fields.indices) {
            val fieldName: String = fields[i].name
            if (!TextUtils.isEmpty(fieldName) && fieldName.startsWith("TAG")) {
                val tag: String = fields[i].get(cls).toString()
                val value: String? = srcExifInterface.getAttribute(tag)
                if (value != null) {
                    dstExifInterface.setAttribute(tag, value)
                }
            }
        }
        dstExifInterface.saveAttributes()
    }

    /**
     * Author: JFangZ
     * Email:janezhang1901@163.com
     * Date:2021/4/26 9:35
     * Description:Scale bitmap by specified factor.
     *
     * @param bitmap Original.
     * @param scale  Scale factor.
     * @return Scaled bitmap.
     */
    fun scale(bitmap: Bitmap, scale: Float): Bitmap? {
        val width = bitmap.width
        val height = bitmap.height
        val matrix = Matrix()
        matrix.postScale(scale, scale)
        return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true)
    }

    /**
     * Author: JFangZ
     * Email:janezhang1901@163.com
     * Date:2021/4/26 9:39
     * Description:Crop bitmap.
     */
    fun crop(bitmap: Bitmap?, startX: Int, startY: Int, stopX: Int, stopY: Int): Bitmap? {
        return Bitmap.createBitmap(bitmap!!, startX, startY, stopX, stopY)
    }

    /**
     * Author: JFangZ
     * Email:janezhang1901@163.com
     * Date:2021/4/26 9:39
     * Description:Merge bitmap.
     */
    fun merge(horizontal: Boolean, vararg bitmaps: Bitmap): Bitmap? {
        var width = 0
        var height = 0
        if (horizontal) {
            for (i in bitmaps.indices) {
                width += bitmaps[i].width
                if (height < bitmaps[i].height) {
                    height = bitmaps[i].height
                }
            }
        } else {
            for (i in bitmaps.indices) {
                if (width < bitmaps[i].width) {
                    width = bitmaps[i].width
                }
                height += bitmaps[i].height
            }
        }
        val result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(result)
        val paint = Paint()
        paint.isAntiAlias = true
        if (horizontal) {
            var left = 0
            for (i in bitmaps.indices) {
                canvas.drawBitmap(bitmaps[i], left.toFloat(), 0f, paint)
                left += bitmaps[i].width
            }
        } else {
            var top = 0
            for (i in bitmaps.indices) {
                canvas.drawBitmap(bitmaps[i], 0f, top.toFloat(), paint)
                top += bitmaps[i].height
            }
        }
        return result
    }

    /**
     * Author: JFangZ
     * Email:janezhang1901@163.com
     * Date:2021/4/26 9:39
     * Description:Mirror bitmap.
     */
    fun mirror(bitmap: Bitmap?, horizontal: Boolean): Bitmap? {
        if (bitmap == null) {
            return null
        }
        val matrix = Matrix()
        if (horizontal) {
            // 左右翻转
            matrix.postScale(-1f, 1f)
        } else {
            // 上下翻转
            matrix.postScale(1f, -1f)
        }
        // 创建翻转后的图片
        return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
    }

    /**
     * Author: JFangZ
     * Email:janezhang1901@163.com
     * Date:2021/4/26 9:39
     * Description:Rotate bitmap.
     */
    fun rotate(bitmap: Bitmap?, degrees: Float): Bitmap? {
        if (bitmap == null) {
            return null
        }
        val matrix = Matrix()
        // 旋转
        matrix.postRotate(degrees, bitmap.width.toFloat() / 2, bitmap.height.toFloat() / 2)
        matrix.postScale(1f, 1f)
        // 创建翻转后的图片
        return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
    }

    /**
     * Author: JFangZ
     * Email:janezhang1901@163.com
     * Date:2021/4/26 9:46
     * Description:Add watermark.
     *
     * @param bitmap    Original.
     * @param watermark Watermark bitmap.
     * @param left      The left of watermark.
     * @param top       The top of watermark.
     * @param right     The right of watermark.
     * @param bottom    The bottom of watermark.
     * @return Added watermark bitmap.
     */
    fun addWatermark(
        bitmap: Bitmap, watermark: Bitmap, left: Int, top: Int, right: Int, bottom: Int
    ): Bitmap? {
        val result = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(result)
        val paint = Paint()
        paint.isAntiAlias = true
        canvas.drawBitmap(bitmap, 0f, 0f, paint)
        canvas.drawBitmap(
            watermark,
            Rect(0, 0, watermark.width, watermark.height),
            Rect(left, top, right, bottom),
            paint
        )
        return result
    }

    /**
     * Author: JFangZ
     * Email:janezhang1901@163.com
     * Date:2021/4/26 9:46
     * Description:Set round corner.
     *
     * @param bitmap Original.
     * @param radius The round corner radius.
     */
    fun roundCorner(bitmap: Bitmap, radius: Float): Bitmap? {
        val result = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(result)
        val paint = Paint()
        paint.isAntiAlias = true
        canvas.drawRoundRect(
            RectF(0f, 0f, bitmap.width.toFloat(), bitmap.height.toFloat()), radius, radius, paint
        )
        paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
        canvas.drawBitmap(bitmap, 0f, 0f, paint)
        return result
    }

    /**
     * Author: JFangZ
     * Email:janezhang1901@163.com
     * Date:2021/4/26 9:47
     * Description:The gray effect.
     *
     * @param bitmap Original.
     */
    fun gray(bitmap: Bitmap): Bitmap? {
        val src = floatArrayOf(
            0.33f,
            0.59f,
            0.11f,
            0f,
            0f,
            0.33f,
            0.59f,
            0.11f,
            0f,
            0f,
            0.33f,
            0.59f,
            0.11f,
            0f,
            0f,
            0f,
            0f,
            0f,
            1f,
            0f
        )
        val result = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
        val colorMatrix = ColorMatrix()
        colorMatrix.set(src)
        val canvas = Canvas(result)
        val paint = Paint()
        paint.isAntiAlias = true
        paint.colorFilter = ColorMatrixColorFilter(colorMatrix)
        canvas.drawBitmap(bitmap, 0f, 0f, paint)
        return result
    }

    /**
     * Author: JFangZ
     * Email:janezhang1901@163.com
     * Date:2021/4/26 9:47
     * Description:The nostalgic effect.
     *
     * @param bitmap Original.
     */
    fun nostalgic(bitmap: Bitmap): Bitmap? {
        val src = floatArrayOf(
            0.393f,
            0.769f,
            0.189f,
            0f,
            0f,
            0.349f,
            0.686f,
            0.168f,
            0f,
            0f,
            0.272f,
            0.534f,
            0.131f,
            0f,
            0f,
            0f,
            0f,
            0f,
            1f,
            0f
        )
        val result = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
        val colorMatrix = ColorMatrix()
        colorMatrix.set(src)
        val canvas = Canvas(result)
        val paint = Paint()
        paint.isAntiAlias = true
        paint.colorFilter = ColorMatrixColorFilter(colorMatrix)
        canvas.drawBitmap(bitmap, 0f, 0f, paint)
        return result
    }

    /**
     * Author: JFangZ
     * Email:janezhang1901@163.com
     * Date:2021/4/26 9:47
     * Description:The desaturated effect.
     *
     * @param bitmap Original.
     */
    fun desaturated(bitmap: Bitmap): Bitmap? {
        val src = floatArrayOf(
            1.5f,
            1.5f,
            1.5f,
            0f,
            -1f,
            1.5f,
            1.5f,
            1.5f,
            0f,
            -1f,
            1.5f,
            1.5f,
            1.5f,
            0f,
            -1f,
            0f,
            0f,
            0f,
            1f,
            0f
        )
        val result = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
        val colorMatrix = ColorMatrix()
        colorMatrix.set(src)
        val canvas = Canvas(result)
        val paint = Paint()
        paint.isAntiAlias = true
        paint.colorFilter = ColorMatrixColorFilter(colorMatrix)
        canvas.drawBitmap(bitmap, 0f, 0f, paint)
        return result
    }

    /**
     * Author: JFangZ
     * Email:janezhang1901@163.com
     * Date:2021/4/26 9:47
     * Description:The saturated effect.
     *
     * @param bitmap Original.
     */
    fun saturated(bitmap: Bitmap): Bitmap? {
        val src = floatArrayOf(
            1.438f,
            -0.122f,
            -0.016f,
            0f,
            -0.03f,
            -0.062f,
            1.378f,
            -0.016f,
            0f,
            0.05f,
            -0.062f,
            -0.122f,
            1.483f,
            0f,
            -0.02f,
            0f,
            0f,
            0f,
            1f,
            0f
        )
        val result = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
        val colorMatrix = ColorMatrix()
        colorMatrix.set(src)
        val canvas = Canvas(result)
        val paint = Paint()
        paint.isAntiAlias = true
        paint.colorFilter = ColorMatrixColorFilter(colorMatrix)
        canvas.drawBitmap(bitmap, 0f, 0f, paint)
        return result
    }

    /**
     * Author: JFangZ
     * Email:janezhang1901@163.com
     * Date:2021/4/26 9:47
     * Description:The negative effect.
     *
     * @param bitmap Original.
     */
    fun negative(bitmap: Bitmap): Bitmap? {
        val width = bitmap.width
        val height = bitmap.height
        var color: Int
        var r: Int
        var g: Int
        var b: Int
        var a: Int
        val result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
        val oldPx = IntArray(width * height)
        val newPx = IntArray(width * height)
        bitmap.getPixels(oldPx, 0, width, 0, 0, width, height)
        for (i in 0 until width * height) {
            color = oldPx[i]
            r = Color.red(color)
            g = Color.green(color)
            b = Color.blue(color)
            a = Color.alpha(color)
            r = 255 - r
            g = 255 - g
            b = 255 - b
            if (r > 255) {
                r = 255
            } else if (r < 0) {
                r = 0
            }
            if (g > 255) {
                g = 255
            } else if (g < 0) {
                g = 0
            }
            if (b > 255) {
                b = 255
            } else if (b < 0) {
                b = 0
            }
            newPx[i] = Color.argb(a, r, g, b)
        }
        result.setPixels(newPx, 0, width, 0, 0, width, height)
        return result
    }

    /**
     * Author: JFangZ
     * Email:janezhang1901@163.com
     * Date:2021/4/26 9:47
     * Description:The old photo effect.
     *
     * @param bitmap Original.
     */
    fun oldPhoto(bitmap: Bitmap): Bitmap? {
        val width = bitmap.width
        val height = bitmap.height
        var color: Int
        var r: Int
        var g: Int
        var b: Int
        var a: Int
        val result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
        val oldPx = IntArray(width * height)
        val newPx = IntArray(width * height)
        bitmap.getPixels(oldPx, 0, width, 0, 0, width, height)
        for (i in 0 until width * height) {
            color = oldPx[i]
            r = Color.red(color)
            g = Color.green(color)
            b = Color.blue(color)
            a = Color.alpha(color)
            r = (0.393 * r + 0.7469 * g + 0.189 * b).toInt()
            g = (0.349 * r + 0.686 * g + 0.168 * b).toInt()
            b = (0.272 * r + 0.534 * g + 0.131 * b).toInt()
            if (r > 255) {
                r = 255
            } else if (r < 0) {
                r = 0
            }
            if (g > 255) {
                g = 255
            } else if (g < 0) {
                g = 0
            }
            if (b > 255) {
                b = 255
            } else if (b < 0) {
                b = 0
            }
            newPx[i] = Color.argb(a, r, g, b)
        }
        result.setPixels(newPx, 0, width, 0, 0, width, height)
        return result
    }

    /**
     * Author: JFangZ
     * Email:janezhang1901@163.com
     * Date:2021/4/26 9:47
     * Description:The relief effect.
     *
     * @param bitmap Original.
     */
    fun relief(bitmap: Bitmap): Bitmap? {
        val width = bitmap.width
        val height = bitmap.height
        var color1: Int
        var color2: Int
        var r1: Int
        var r2: Int
        var g1: Int
        var g2: Int
        var b1: Int
        var b2: Int
        var a1: Int
        var a2: Int
        val result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
        val oldPx = IntArray(width * height)
        val newPx = IntArray(width * height)
        bitmap.getPixels(oldPx, 0, width, 0, 0, width, height)
        for (i in 1 until width * height) {
            color1 = oldPx[i - 1]
            r1 = Color.red(color1)
            g1 = Color.green(color1)
            b1 = Color.blue(color1)
            a1 = Color.alpha(color1)
            color2 = oldPx[i]
            r2 = Color.red(color2)
            g2 = Color.green(color2)
            b2 = Color.blue(color2)
            r1 = r1 - r2 + 127
            g1 = g1 - g2 + 127
            b1 = b1 - b2 + 127
            if (r1 > 255) {
                r1 = 255
            } else if (r1 < 0) {
                r1 = 0
            }
            if (g1 > 255) {
                g1 = 255
            } else if (g1 < 0) {
                g1 = 0
            }
            if (b1 > 255) {
                b1 = 255
            } else if (b1 < 0) {
                b1 = 0
            }
            newPx[i] = Color.argb(a1, r1, g1, b1)
        }
        result.setPixels(newPx, 0, width, 0, 0, width, height)
        return result
    }

    /**
     * Author: JFangZ
     * Email:janezhang1901@163.com
     * Date:2021/4/26 9:47
     * Description:The black and white effect.
     *
     * @param bitmap Original.
     */
    fun blackAndWhite(bitmap: Bitmap): Bitmap? {
        val width = bitmap.width
        val height = bitmap.height
        var color: Int
        var r: Int
        var g: Int
        var b: Int
        var a: Int
        val result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
        val oldPx = IntArray(width * height)
        val newPx = IntArray(width * height)
        bitmap.getPixels(oldPx, 0, width, 0, 0, width, height)
        for (i in 0 until width * height) {
            color = oldPx[i]
            a = Color.alpha(color)
            // 分离三原色
            r = color and 0x00FF0000 shr 16
            g = color and 0x0000FF00 shr 8
            b = color and 0x000000FF

            // 转化成灰度像素
            color = (r * 0.3 + g * 0.59 + b * 0.11).toInt()
            color = a shl 24 or (color shl 16) or (color shl 8) or color
            newPx[i] = color
        }
        result.setPixels(newPx, 0, width, 0, 0, width, height)
        return result
    }

    /**
     * Author: JFangZ
     * Email:janezhang1901@163.com
     * Date:2021/4/26 9:47
     * Description:The reflection effect.
     *
     * @param bitmap Original.
     */
    fun reflection(bitmap: Bitmap): Bitmap? {
        val reflectionGap = 4
        val width = bitmap.width
        val height = bitmap.height
        val matrix = Matrix()
        matrix.preScale(1f, -1f)
        val reflectionBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, false)
        val result = Bitmap.createBitmap(width, height * 2, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(result)
        canvas.drawBitmap(bitmap, 0f, 0f, null)
        val paint = Paint()
        paint.isAntiAlias = true
        canvas.drawRect(
            0f, height.toFloat(), width.toFloat(), (height + reflectionGap).toFloat(), paint
        )
        canvas.drawBitmap(reflectionBitmap, 0f, (height + reflectionGap).toFloat(), null)
        val shader = LinearGradient(
            0f,
            bitmap.height.toFloat(),
            0f,
            result.height.toFloat() + reflectionGap,
            0x70FFFFFF,
            0x00FFFFFF,
            Shader.TileMode.CLAMP
        )
        paint.reset()
        paint.shader = shader
        // Set the Transfer mode to be porter duff and destination in
        paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_IN)
        // Draw a rectangle using the paint with our linear gradient
        canvas.drawRect(
            0f, height.toFloat(), width.toFloat(), (result.height + reflectionGap).toFloat(), paint
        )
        return result
    }

    /**
     * Author: JFangZ
     * Email:janezhang1901@163.com
     * Date:2021/4/26 9:47
     * Description:The cover effect.
     *
     * @param bitmap Original.
     */
    fun cover(bitmap: Bitmap, alpha: Int): Bitmap? {
        val width = bitmap.width
        val height = bitmap.height
        val result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(result)
        val paint = Paint()
        paint.isAntiAlias = true
        canvas.drawARGB(alpha, 0, 0, 0)
        paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_OVER)
        canvas.drawBitmap(bitmap, 0f, 0f, paint)
        return result
    }

    /**
     * Author: JFangZ
     * Email:janezhang1901@163.com
     * Date:2021/5/8 19:30
     * Description:Draw src where the src and the dst intersect.
     */
    fun srcIn(src: Bitmap, dst: Bitmap): Bitmap? {
        val result = Bitmap.createBitmap(src.width, src.height, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(result)
        val paint = Paint()
        paint.isAntiAlias = true
        canvas.drawBitmap(
            src, Rect(0, 0, src.width, src.height), Rect(0, 0, result.width, result.height), paint
        )
        // 在源图像和目标图像相交的地方绘制源图像,源图像为后画的图像,目标图像为先画的图像
        paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
        canvas.drawBitmap(
            dst, Rect(0, 0, dst.width, dst.height), Rect(0, 0, result.width, result.height), paint
        )
        return result
    }

    /**
     * Author: JFangZ
     * Email:janezhang1901@163.com
     * Date:2021/4/26 9:47
     * Description:The gaussian blur effect.
     *
     * @param bitmap Original.
     */
    fun gaussian(bitmap: Bitmap): Bitmap? {
        //水平方向模糊度
        val hRadius = 10f
        //竖直方向模糊度
        val vRadius = 10f
        //模糊迭代度
        val iterations = 7
        val width = bitmap.width
        val height = bitmap.height
        val inPixels = IntArray(width * height)
        val outPixels = IntArray(width * height)
        val result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
        bitmap.getPixels(inPixels, 0, width, 0, 0, width, height)
        for (i in 0 until iterations) {
            blur(inPixels, outPixels, width, height, hRadius)
            blur(outPixels, inPixels, height, width, vRadius)
        }
        blurFractional(inPixels, outPixels, width, height, hRadius)
        blurFractional(outPixels, inPixels, height, width, vRadius)
        result.setPixels(inPixels, 0, width, 0, 0, width, height)
        return result
    }

    fun getDegree(path: String): Int {
        var degree = 0
        try {
            // Get Exif.
            val exifInterface = ExifInterface(path)
            // Get rotate.
            val orientation = exifInterface.getAttributeInt(
                ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL
            )
            when (orientation) {
                ExifInterface.ORIENTATION_ROTATE_90 -> degree = 90
                ExifInterface.ORIENTATION_ROTATE_180 -> degree = 180
                ExifInterface.ORIENTATION_ROTATE_270 -> degree = 270
            }
        } catch (e: IOException) {
            e.printStackTrace()
        }
        return degree
    }
}